import { t } from "./analysis";
import * as vscodels from "vscode-languageserver";

export function provideFoldingRanges(source: t.SourceFile) {
    let ranges: vscodels.FoldingRange[] = [];
    // comments
    for (const comment of source.comments) {
        // block comments
        if (comment.comments.length > 1) {
            let startPos = source.getLineAndCharactorOfPosition(comment.start);
            let endPos = source.getLineAndCharactorOfPosition(comment.end);
            ranges.push(vscodels.FoldingRange.create(startPos.line, endPos.line, startPos.character, endPos.character, vscodels.FoldingRangeKind.Comment));
        }
    }
    // child nodes
    source.forEachChild(
        node => {
            let nodeRanges = getFoldingRange(node, source);
            if (nodeRanges) {
                ranges.push(...nodeRanges);
            }
        },
        nodeArray => {
            for (const node of nodeArray) {
                let nodeRanges = getFoldingRange(node, source);
                if (nodeRanges) {
                    ranges.push(...nodeRanges);
                }
            }
        });
    return ranges;
}

function getFoldingRange(node: t.Node, source: t.SourceFile): vscodels.FoldingRange[] {
    let ranges: vscodels.FoldingRange[] = [];
    let folding = getNodeFoldingRange(node, source);
    if (folding) {
        ranges.push(...folding);
    }
    node.forEachChild(n => {
        const childFolding = getFoldingRange(n, source);
        ranges.push(...childFolding);
    });
    return ranges;
}

function getNodeFoldingRange(node: t.Node, source: t.SourceFile): vscodels.FoldingRange[] {
    let result: vscodels.FoldingRange[] = [];
    let start: t.TextPosition, end: t.TextPosition;
    switch (node.kind) {
        case t.SyntaxKind.ifStat:
        case t.SyntaxKind.ppIf:
        case t.SyntaxKind.ppIfNDef:
        case t.SyntaxKind.ppIfDef:
            let ifNode = node as (t.IfStat | t.PPIf | t.PPIfNDef | t.PPIfDef);
            if (ifNode.isStatement<t.IfStat>(t.SyntaxKind.ifStat) && ifNode.singleLine) {
                break;
            }
            start = source.getLineAndCharactorOfPosition(ifNode.start);
            end = source.getLineAndCharacterOfLastLineEndPosition(ifNode.elseKeyword ? ifNode.elseKeyword.start : ifNode.end);
            result.push(vscodels.FoldingRange.create(start.line, end.line, start.character, end.character));
            if (ifNode.elseKeyword) {
                start = source.getLineAndCharactorOfPosition(ifNode.elseKeyword.start);
                end = source.getLineAndCharacterOfLastLineEndPosition(ifNode.end);
                result.push(vscodels.FoldingRange.create(start.line, end.line, start.character, end.character));
            }
            break;
        case t.SyntaxKind.forStat:
        case t.SyntaxKind.forEachStat:
        case t.SyntaxKind.doStat:
        case t.SyntaxKind.whileStat:
        case t.SyntaxKind.selectCaseClause:
        case t.SyntaxKind.selectStat:
        case t.SyntaxKind.withStat:
        case t.SyntaxKind.sectionStat:
        case t.SyntaxKind.funcDecl:
        case t.SyntaxKind.enumSignature:
        case t.SyntaxKind.classSignature:
        case t.SyntaxKind.moduleSignature:
        case t.SyntaxKind.interfaceSignature:
        case t.SyntaxKind.jobSection:
        case t.SyntaxKind.eventSection:
        case t.SyntaxKind.loggingSection:
        case t.SyntaxKind.routingSection:
        case t.SyntaxKind.metadataSection:
        case t.SyntaxKind.inputDataSourceSection:
        case t.SyntaxKind.outputDataSourceSection:
        case t.SyntaxKind.globalSQLVariablesSection:
            start = source.getLineAndCharactorOfPosition(node.start);
            end = source.getLineAndCharacterOfLastLineEndPosition(node.end);
            result.push(vscodels.FoldingRange.create(start.line, end.line, start.character, end.character));
            break;
    }
    return result;
}
